package com.gitee.wsl.net.client

import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import kotlinx.io.IOException
import kotlinx.serialization.SerializationException
import io.ktor.client.network.sockets.ConnectTimeoutException
import timber.log.Timber

open class BaseNetworkService(private val ioDispatcher: CoroutineDispatcher) {
    protected suspend fun <T> apiRequest(
        suspendBlock: suspend () -> T
    ): T = withContext(ioDispatcher) {
        makeRequest {
            suspendBlock.invoke()
        }
    }

    @Suppress("TooGenericExceptionCaught")
    private suspend fun <T> makeRequest(
        suspendBlock: suspend () -> T
    ): T = try {
        suspendBlock.invoke()
    } catch (e: Throwable) {
        throw when (e) {
            is CancellationException -> TerminationException(e)
            is ConnectTimeoutException -> TimeoutException(e)
            is IOException -> NetworkException(e)
            is SerializationException -> ModelMappingException(e)
            else -> UnknownNetworkException(e)
        }
    }

    protected fun withEmptyParameterCheck(parameter: String) = parameter.ifEmpty {
        EmptyParameterException().let {
            Timber.e(it)
            throw it
        }
    }
}

internal class EmptyParameterException : Exception("parameter can not be empty")

internal class ModelMappingException(cause: Throwable) : Throwable(cause)

internal class NetworkException(cause: Throwable) : Throwable(cause)

internal class TerminationException(cause: Throwable) : Throwable(cause)

internal class TimeoutException(cause: Throwable) : Throwable(cause)

internal class UnknownNetworkException(cause: Throwable) : Throwable(cause)
